package org.xiaoxin.onecoupon.merchant.admin.service.handler.delayqueue;

import com.alibaba.fastjson2.JSONObject;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RedissonClient;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Service;
import org.xiaoxin.onecoupon.merchant.admin.dao.entity.CouponTaskDO;
import org.xiaoxin.onecoupon.merchant.admin.dao.mapper.CouponTaskMapper;
import org.xiaoxin.onecoupon.merchant.admin.service.CouponTaskService;

import java.util.concurrent.Executors;

/**
 * 定义延时队列消费者
 * 优惠券延迟刷新发送条数兜底消费者｜这是兜底策略，一般来说不会执行这段逻辑
 * @author xiaoxin
 * 2025/4/19
 */
@Service
@RequiredArgsConstructor
class RefreshCouponTaskDelayQueueRunner implements CommandLineRunner {
   private final RedissonClient redissonClient;
   private  final CouponTaskMapper couponTaskMapper;

   private  final CouponTaskService couponTaskService;

   @Override
   public void run(String... args) throws Exception {
       /**
        * 实现 CommandLineRunner 接口在项目启动后运行后置任务。流程如下：
        * 1.启动一个线程，在线程无限循环获取 Redis 阻塞队列已经到达时间的元素；
        * 2.然后判断数据库中的分发任务 Excel 总数是否为空，为空读取 Excel 记录，然后设置；如果不为空证明线程池已经运行完了。
        */
      Executors.newSingleThreadExecutor(
                      //runnable -> { ... }：这是一个 Lambda 表达式，用于自定义线程池中线程的创建方式。
                      runnable ->{
                         Thread thread = new Thread(runnable);
                         thread.setName("delay_coupon-task_send-num_consumer");
                         //将线程设置为守护线程
                         thread.setDaemon(Boolean.TRUE);
                         return  thread;
                      })
              .execute(()->{
                 RBlockingDeque<JSONObject> blockingDeque = redissonClient.getBlockingDeque("COUPON_TASK_SEND_NUM_DELAY_QUEUE");
                 //这是一个无限循环，表示消费者会一直运行，不断从队列中获取任务
                 for(;;){
                    try {
                        //blockingDeque.take()：从阻塞队列中取出一个元素。如果队列为空，线程会阻塞，直到有元素可用。
                       JSONObject delayJsonObject=blockingDeque.take();
                       if (delayJsonObject!=null){
                          CouponTaskDO couponTaskDO = couponTaskMapper.selectById(delayJsonObject.getLong("couponTaskId"));
                          if (couponTaskDO.getSendNum() == null){
                             couponTaskService.refreshCouponTaskSendNum(delayJsonObject);
                          }
                       }
                    } catch (Throwable ignored) {
                    }
                 }

              });

   }
}
